/*
    建立消息类型与处理函数的映射关系
*/

#pragma once

#include "net.hpp"

namespace myrpc
{
    //方便存储针对不同类型消息导致类型不一致的回调函数，降低用户注册成本
    //在注册时只需指明针对的消息类型，就可生成对应的回调函数类型，注册时更加方便
    class Callback
    {
    public:
        typedef std::shared_ptr<Callback> ptr;
        virtual void onMessage(const BaseConnection::ptr& conn, BaseMessage::ptr& msg) = 0;
    };

    template<class T>
    class CallbackT : public Callback
    {
    public:
        typedef std::shared_ptr<CallbackT<T>> ptr;
        typedef MessageCallback std::function<void(const BaseConnection::ptr&, std::shared_ptr<T>&)>;
    
        CallbackT(const T& hander) :_hander(hander) {}
        virtual void onMessage(const BaseConnection::ptr& conn, BaseMessage::ptr& msg) override
        {
            auto type_msg = std::dynamic_pointer_cast<T>(msg);
            _hander(conn, type_msg);
        }
    private:
        MessageCallback _hander;
    };

    class Dispatcher
    {
    public:
        typedef std::shared_ptr<Dispatcher> ptr;

        template<class T>
        void RegisterHander(MType mtype, const typename CallbackT<T>::MessageCallback& hander)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto cb = std::make_shared<CallbackT<T>>(hander);
            _handers.insert({mtype, cb});
        }

        void onMessage(const BaseConnection::ptr& conn, BaseMessage::ptr& msg)
        {
            //寻找消息类型对应的业务处理函数，并调用
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _handers.find(msg->mtype());
            if(it != _handers.end())
            {
                it->second->onMessage(conn, msg);
            }
            else
            {
                ELOG("未知类型的消息");
                conn->shutdown();
            }
        }
    private:
        std::unordered_map<MType, Callback::ptr> _handers;
        std::mutex _mutex;
    };
}
